local helper= require 'library.helpers'
local vaild = {}

function vaild:init_functions()
	self:add_function("eq",function(data,p1)
		return tostring(data)==p1
	end)

	self:add_function("match",function(data,p1)
		local match=ngx.re.match(data,p1)
		return not not match
	end)

	self:add_function("min_length",function(data,p1)
		p1=tonumber(p1)
		local size=#data
		return size>p1
	end)

	self:add_function("max_length",function(data,p1)
		p1=tonumber(p1)
		local size=#data
		return size<p1
	end)

	self:add_function("exact_length",function(data,p1)
		p1=tonumber(p1)
		local size=#data
		return size==p1
	end)

	self:add_function("email",function(data)
		local match=ngx.re.match(data,"^([a-z0-9\\+_\\-]+)(\\.[a-z0-9\\+_\\-]+)*@([a-z0-9\\-]+\\.)+[a-z]{2,6}$",'ix')
		return not not match
	end)	


	self:add_function("alpha",function(data)
		local match=ngx.re.match(data,"^[a-z]+$",'i')
		return not not match
	end)

	self:add_function("alpha_number",function(data)
		local match=ngx.re.match(data,"^[a-z0-9]+$",'i')
		return not not match
	end)

	self:add_function("is_numeric",function(data)
		return helper:is_numeric(data)
	end)

	self:add_function("int",function(data)
		return helper:is_int(data)
	end)

	self:add_function("is_natural",function(data)
		return helper:is_natural(data)
	end)

	self:add_function("is_natural_no_zero",function(data)
		return helper:is_natural_no_zero(data)
	end)

	self:add_function("base64",function(data)
		local match=ngx.re.match(data,"^[^a-zA-Z0-9\\/\\+=]")
		return not not match
	end)

	self:add_function("emails",function(data)
		local emails=helper:split(data,',')
		for _,v in ipairs(emails) do
			if not self.functions['email'](v) then
				return false
			end
		end
		
		return true
	end)

	self:add_function("ip",function(data)
		local ip=helper:split(data,'.')

		if #ip ~=4 then
			return false
		end

		if helper:substr(ip[0],1,'')=='0' then
			return false
		end

		for i=1,4 do
			local m= ngx.re.match(ip[i],"[^0-9]")
			if ip[i]=='' or m or tonumber(ip[i])>255  or #ip[i]>3 then
				return false
			end
		end

		return false
	end)

end

function vaild:new(data)
	local v={
		rules={},
		msgs={},
		errors={},
		functions={},
		splits={},
		data=data
	}
	setmetatable(v,{__index=self})
	v:init_functions();
	return v
end

function vaild:add(key,rule,msg,s)
	s=s or ','
	self.rules[key]=rule
	self.msgs[key]=msg
	self.splits[key]=s
end

function vaild:add_error(key,msg,rule)
	self.errors[key]=msg --.."-"..rule
end

function vaild:get_errors()
	return self.errors
end

function vaild:add_function(key,fun)
	self.functions[key]=fun;
end

function vaild:run()
	for key,rule in pairs(self.rules) do
		local data=self.data[key]
		local rules=helper:split(rule,"|")
		local is_required=helper:in_table("required",rules)

		if not data or data=="" then
			if is_required then
				self:add_error(key,self.msgs[key],'required')
				return false
			end
		else
			-- run rules
			for _,v in ipairs(rules) do
				if v~="required" then
					local match=ngx.re.match(v,'\\((.+)\\)')
					local params={}

					if match then
						local s=self.splits[key] or ','
						params=helper:split(match[1],s)
						v=ngx.re.sub(v,"\\(.+\\)","")
					end

					-- if self.functions[v] then
					-- 	print_r(params)
					-- 	print_r(self.functions[v](data,unpack(params)))
					-- end

					if not self.functions[v] or not self.functions[v](data,unpack(params)) then
						self:add_error(key,self.msgs[key],v)
						return false
					end
				end
			end
		end
	end
	return true
end


return vaild